package com.sprouting.personal.model.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sprouting.personal.annotations.CheckLength;
import com.sprouting.personal.annotations.CheckNotNull;
import com.sprouting.personal.model.common.BaseModel;
import com.sprouting.personal.model.common.jsr.AddGroup;
import com.sprouting.personal.model.common.jsr.UpdGroup;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import java.util.Date;

/**
 * 计划表
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2023/1/10 14:01
 */
@TableName("ps_plan")
@Data
public class PsPlan extends BaseModel {

    /*
        2023年1月10日14:03:19
        写这个功能的时候是非常纠结的，如果正常编写的话，这里使用 cron 表达式是最合适的，但根据我的使用经验，这个项目中有一个非常重要的功能，就是提前进行提醒，比如10天后要进行某个任务，
        但希望在7天前就可以进行任务提醒，做不做是你的事情，到了10天后还没做，那任务就过期，但需要进行提前来完成。
        同时，这一个版本还有一个大改动，就是循环任务给细化到了小时这个级别，之前1.0的时候最大颗粒度都在天，这就会导致一个问题，如果到了小时级别，那么提前提醒就变麻烦了，要考虑到这个提前提醒
        将前面一次的任务都进行了覆盖，同时，因为有这种当天的任务，可能还需要进行任务的推送，那是不是要引入 websocket 了?
        但这个任务算是这个功能里面的一个大头，需要进行考虑，但也要有一定的取舍。

        下面的也算是理一下吧，个人分析，任务分了2种。
        1、最常用的就是定时任务，定时任务暂时都是定的到 年月日， 因为这种定时任务很多情况下用于 XX天要进行换证，X天要进行要做什么，一定会有提前提醒的工作。
        2、循环任务，这种循环几个常见例子，缴纳月保提醒、每天读单词  这种按月的可以进行提前提醒，按照天的不适合。且都应该是 年月日，这种循环提醒还可能是三天一次，一周一次，一年一次。循环任务
        有些还是有期限的，比如从10号开始到20号结束，其他的时间就不进行

        下面是这次升级如果加了任务可能会增加的功能，比如 指定到时分秒的定时任务，这种其实一般最近几天的任务调度，一般比如工作任务的提醒，需要精确到时分秒，不适合进行提前提醒。
        到分、小时级别的循环提醒，比如喂奶等等。过多久检查一次洗衣服是否完成，是否烧水烧好了。

        通过上面的一些分析，感觉差不多可以确定范围，有些需求需要砍掉。并不是特别的重要。如此，确定范围
        1、常见的定时任务，年月日，可以提前多久进行提醒，可以提前完成，完成后进入完成库，过期进入未完成库
        2、循环任务，按照天级别的提醒，可以进行调度，多久执行一次，最好可以显示未来5天的任务，这种不进行提前提醒。只有月级别的才进行提前提醒
        3、按照分钟级别的提醒不做，最低到一个小时的级别，每一个小时调用一次，不进行提前提醒
        4、固定时间到时分秒的提醒，这种是做强提醒。
        5、循环任务给最近5次的执行记录，没有则提示

        会有的问题，暂时为了项目的复杂度，不会去做成前后通讯的，而是前端的定时任务调度，这会导致几个问题，1是前端可能就永远无法退出了，放在那里也不会下线，不安全，当然这个可以设置session
        第二个，就是暂定前端半个小时调度一次，刷新一次，但这个时间不会是特别精确，因为半小时一次的唤醒，会在后台还要进行任务计算，所以，可能1个小时后执行的任务，到了1个小时1分后才真正的
        进行了执行。

        对于循环任务，比如1个小时一次的，第一次没有执行，那么进入到逾期，不会继续进行任务
        下次要进行一次冲正?如果忘记打开应用导致逾期过的？
        是的，否则会有一堆任务，直接进行一次处理，到最新的时间点完成即可
    * */

    /**
     * 主键
     */
    @TableId
    @CheckNotNull(message = "非法ID", groups = UpdGroup.class)
    @Null(message = "无效ID", groups = AddGroup.class)
    private String id;
    /**
     * 隶属用户
     */
    private String userId;
    /**
     * 计划名称
     */
    @CheckLength(min = 1, max = 300, message = "计划名称超过长度限制")
    @CheckNotNull(message = "请输入计划名称")
    private String name;
    /**
     * 计划类型-固定，循环
     * @see com.sprouting.personal.interfaces.common.Constant.TaskPlanType
     */
    @NotNull(message = "请选择计划类型")
    private Integer type;
    /**
     * 周期
     * 多久执行一次
     */
    private Integer cycle;
    /**
     * 重要性
     * @see com.sprouting.personal.interfaces.common.Constant.ImportanceLevel
     */
    private Integer importance;
    /**
     * 开始时间
     * 循环任务有时候有开始时间，定时任务的数据也是放在这里，但定时任务的开始和结束时间都是一致的
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @NotNull(message = "必须指定任务开始时间")
    private Date startTime;
    /**
     * 停止时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTime;
    /**
     * 最近一次任务提交时间-完成时间
     * 2023年8月30日 不能记录完成时间，而应该记录本次应该执行的时间，比如1、3、5 各自执行一次，现在是2，但也可以提前一天执行，记录的数据也应该是1、3、5
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date executeLastTime;
    /**
     * 计划详情
     */
    private String details;
    /**
     * 分类，家庭、工作、个人
     * @see com.sprouting.personal.interfaces.common.Constant.TaskClassify
     */
    private Integer classify;
    /**
     * 提前多久提醒-单位天
     * 注意，这个时间不能超过今天到任务的时间
     * 到了这个时间，也表示可以开始执行了
     * 到了天级别就不允许提前提醒了，月，提前提醒不能超过28天。年 提前提醒不能超过365天
     */
    private Integer advance;
    /**
     * 是否完成
     * @see com.sprouting.personal.interfaces.common.Constant.TaskFinish
     */
    private Integer finish;
}
